package cn.pangza.user.service;

import cn.pangza.common.exception.BusinessException;
import cn.pangza.common.utils.StringUtil;
import cn.pangza.user.constant.TokenConstData;
import cn.pangza.user.entity.po.SystemUserPo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public class TokenService {

    public static String generateToken(SystemUserPo user) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        List<String> authoritiesString = authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList());
        String resultAuthorities = String.join(",", authoritiesString);
        String token = Jwts.builder().signWith(SignatureAlgorithm.HS512, TokenConstData.TOKEN_SIGN)
                .setSubject(authentication.getName())
                .claim("userId", user.getId())
                .claim("authorities", resultAuthorities)
                .compact();
        return token;
    }


    public static Authentication checkToken(String token) throws BusinessException {
        token = token.replace("Bearer ", "");

        if(StringUtil.isEmpty(token)) {
            throw new BusinessException(TokenConstData.TOKEN_ERROR_MESSAGE);
        }
        Claims body = null;
        try {
            body = Jwts.parser().setSigningKey(TokenConstData.TOKEN_SIGN).parseClaimsJws(token).getBody();
            if(ObjectUtils.isEmpty(body)) {
                throw new BusinessException(TokenConstData.TOKEN_ERROR_MESSAGE);
            }
            String username = body.getSubject();
            String authoritiesString = (String) body.get("authorities");
            List<SimpleGrantedAuthority> authorities = new ArrayList<>();
            if(StringUtil.isNotEmpty(authoritiesString)) {
                authorities = Arrays.stream(authoritiesString.split(",")).map(SimpleGrantedAuthority::new).collect(Collectors.toList());
            }
            UsernamePasswordAuthenticationToken authenticated = UsernamePasswordAuthenticationToken.authenticated(username, null, authorities);
            SystemUserPo systemUserPo = new SystemUserPo();
            systemUserPo.setId((Integer) body.get("userId"));
            systemUserPo.setUsername(username);
            authenticated.setDetails(systemUserPo);
            return authenticated;
        } catch (ExpiredJwtException e) {
            throw new BusinessException(TokenConstData.TOKEN_EXPIRE_MESSAGE);
        }
    }

    public static Integer getUserId(String token) throws BusinessException {
        token = token.replace("Bearer ", "");

        if(StringUtil.isEmpty(token)) {
            throw new BusinessException(TokenConstData.TOKEN_ERROR_MESSAGE);
        }
        Claims body = null;
        try {
            body = Jwts.parser().setSigningKey(TokenConstData.TOKEN_SIGN).parseClaimsJws(token).getBody();
            if(ObjectUtils.isEmpty(body)) {
                throw new BusinessException(TokenConstData.TOKEN_ERROR_MESSAGE);
            }
            return (Integer) body.get("userId");
        } catch (ExpiredJwtException e) {
            throw new BusinessException(TokenConstData.TOKEN_EXPIRE_MESSAGE);
        }
    }

}
